//********************************************************************************************************************//
//ORGANIZATION:
//AUTHOR: bpeng(bogers.peng@gmail.com)
//SUMMARY:
//********************************************************************************************************************//
#ifndef NATIVE_SYSTEM_BASE_ARRAYITERATOR_H
#define NATIVE_SYSTEM_BASE_ARRAYITERATOR_H

#ifndef NATIVE_SYSTEM_BASE_ARRAY_H
#include "System/Base/Array.h"
#endif
#ifndef NATIVE_SYSTEM_BASE_ITERATE_H
#include "System/Base/Iterate.h"
#endif

namespace Native { namespace System
{
    //************************************************************************************************************//
    //CArrayIterator
    //
    //************************************************************************************************************//
    template<typename _TElement, bool _FORWARD = true>
    class NATIVE_LIBRARY_EXPORT CArrayIterator :
        public CObject,
        public IIterate<_TElement>
    {
        NATIVE_DECLARE_OBJECT;

        NATIVE_REDEFINE(public, _TElement, TElement, T_ELEMENT);
        NATIVE_REDEFINE(public, CArrayIterator<TElement COMMA _FORWARD>, Class, CLASS);

    protected:
        const CArray<TElement>* _array;
        CArrayCursor _cursor;
        TElement _current;

    protected:
        void _March()
        {
            _FORWARD? _cursor.Forward() : _cursor.Back();
            _current = _array->Get(_cursor.Index());
        }

    protected:
        CArrayIterator() :
            _array(nullptr)
        {};
    public:
        CArrayIterator(CLASS& that) :
            CObject(that),
            _array(that._array),
            _cursor(that._cursor),
            _current(that._current)
        {};

        CArrayIterator(CLASS&& that) :
            CObject(that),
            _array(that._array),
            _cursor(that._cursor),
            _current(that._current)
        {};

        CArrayIterator(const CArray<TElement>* array) throw()
        {
            //Detect null pointer of array, then later method need not check it.
            CNullPointerException::Check(NATIVE_SCENE(L"CArrayIterator"), (POINTER)array, L"array");

            _array = array;
        };

        virtual ~CArrayIterator()
        {};

        virtual TElement* First()
        {
            _FORWARD? _cursor = _array->LocateFirst() : _cursor = _array->LocateLast();

            if (_cursor.Exist()) {
                _current = _array->Get(_cursor.Index());

                return &_current;
            } else {
                return nullptr;
            }
        };

        virtual TElement* Next()
        {
            if (_cursor.Exist()) {
                if (Done()) {
                    return nullptr;
                } else {
                    _March();

                    return &_current;
                }
            } else {
                return nullptr;
            }
        };

        virtual bool Done() const
        {
            if (_cursor.Exist()) {
                return _FORWARD? _array->AtEnding(_cursor.Index()) : _array->AtBeginning(_cursor.Index());
            } else {
                return true;
            }
        };

        virtual TElement* Current()
        {
            return _cursor.Exist()? &_current : nullptr;
        };

        CLASS& operator=(CLASS& rvalue)
        {
            CObject::operator=(rvalue);

            _array = rvalue._array;
            _cursor = rvalue._cursor;
            _current = rvalue._current;

            return *this;
        };
    };
}}

#endif